package com.fourpigeon.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.fourpigeon.dao.UserDao;
import com.fourpigeon.domain.Result;
import com.fourpigeon.utils.COSUtils;
import com.fourpigeon.utils.SystemConstants;
import com.fourpigeon.utils.UserHolder;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.fourpigeon.utils.RedisConstants.*;

@Slf4j
@RestController
@RequestMapping("/upload")
public class UploadController {
    @Autowired
    private UserDao userDao;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private COSUtils cosUtils;


    private static String IMAGE_UPLOAD_DIR = "";
    private Random random = new Random();

    /**
     * 上传图片
     * @param images 图片数组
     * @param loginType 登录状态
     * @return 图片路径
     */
    @PostMapping("/blog/{loginType}")
    public String uploadImage(@RequestParam("file")MultipartFile[] images,@PathVariable boolean loginType){
        StringBuilder result = new StringBuilder();
        for (int i = 0;i<images.length;i++) {
            MultipartFile image = images[i];
            //获取文件原始名称
            String originalFilename = image.getOriginalFilename();
            //生成文件名
            String filePath = createNewFileName(originalFilename);
            String bucketName = "kestrel-1319254659";
            //拼接路径
            String key = "imgs"+filePath;
            File file = multipartFileToFile(image);
            if(loginType){
                Long id = UserHolder.getUser().getId();
                LocalDateTime createTime = userDao.getById(id).getCreateTime();
                //计算差值
                Duration between = Duration.between(createTime,LocalDateTime.now());
                //如果是10s以内注册的用户，上传头像
                if (between.toDays()==0&&between.toHours()==0&&between.toMinutes()==0&&between.toSeconds()<=10) {
                    try{
                        //上传图片
                        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName,key,file);
                        PutObjectResult putObjectResult = COSUtils.cosClient.putObject(putObjectRequest);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    //图片记录Redis
                    stringRedisTemplate.opsForSet().add(UPLOAD_FILE_SET,filePath);
                    //保存路径到SQL数据库
                    userDao.updateIcon(id, key);
                    stringRedisTemplate.opsForSet().add(UPLOAD_FILE_CONFIRM_SET,filePath);
                    //返回结果
                    log.debug("文件上传成功，{}",key);
                    FileUtil.del(file);
                    return key;
                }
                FileUtil.del(file);
                return "";
            }
            //上传图片
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName,key,file);
            PutObjectResult putObjectResult = COSUtils.cosClient.putObject(putObjectRequest);
            //保存Redis记录
            stringRedisTemplate.opsForSet().add(UPLOAD_FILE_SET,key);
            //暂存，若长时间未上传，加入删除行列
            stringRedisTemplate.opsForValue().set(UPLOAD_FILE_CONFIRM_STRING+key,"0");
            stringRedisTemplate.expire(UPLOAD_FILE_CONFIRM_STRING+key,30L+ random.nextInt(2),TimeUnit.MINUTES);
            //返回结果
            log.debug("文件上传成功，{}",key);
            if(i > 0) result.append(',');
            result.append(key);
            //处理流传输生成的临时图片文件
            FileUtil.del(file);
        }
        return result.toString();
    }

    /**
     * 根据路径删除存储桶中的图片
     * @param filePath 图片链接
     * @return 空
     */
    @GetMapping("/blog/delete")
    public Result deleteBlogImage(@RequestParam("name") String filePath){
        String bucketName = SystemConstants.TX_BUCKET_NAME;
        COSUtils.cosClient.deleteObject(bucketName,filePath);
        return Result.ok();
    }

    /**
     * 获取存储桶临时凭证
     * @return List
     */
    @GetMapping("/cos/tmpInfo")
    public Result getCosTmpInfo(){
        List<String> result = new ArrayList<>(3);
        result.add(SystemConstants.TX_TMP_SECRET_ID);
        result.add(SystemConstants.TX_TMP_SECRET_KEY);
        result.add(SystemConstants.TX_TMP_SESSION_TOKEN);
        return Result.ok(result);
    }

    /**
     * MultipartFile转换成File
     * @param image 图片文件
     * @return File
     */
    private File multipartFileToFile(MultipartFile image) {
        File file = new File(image.getOriginalFilename());
        //使用try with resources结构使out自动关闭
        //获取文件流
        try(OutputStream out = new FileOutputStream(file)){
            byte[] ss = image.getBytes();
            for (byte s : ss) {
                out.write(s);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 上传图片
     * @param image 图片
     * @return 图片文件路径
     */
    @Deprecated
//    @PostMapping("/blog/{loginType}")
    public Result uploadImage1(@RequestParam("file")MultipartFile image,@PathVariable boolean loginType){
        try{
            //获取文件原始名称
            String originalFilename = image.getOriginalFilename();
            //在生成本地文件名
            String fileName = createNewFileName(originalFilename);
            if (loginType) {
                //获取用户信息
                Long id = UserHolder.getUser().getId();
                LocalDateTime createTime = userDao.getById(id).getCreateTime();
                //计算差值
                Duration between = Duration.between(createTime, LocalDateTime.now());
                //如果是5s以内注册的用户，上传头像
                if (between.toDays()==0&&between.toHours()==0&&between.toMinutes()==0&&between.toSeconds()<=5) {
                    //保存文件到本地
                    image.transferTo(new File(IMAGE_UPLOAD_DIR,fileName));
                    //TODO 记录Redis
                    stringRedisTemplate.opsForSet().add(UPLOAD_FILE_SET,fileName);
                    //保存路径到SQL数据库
                    userDao.updateIcon(id, fileName);
                    stringRedisTemplate.opsForSet().add(UPLOAD_FILE_CONFIRM_SET,fileName);
                    //返回结果
                    log.debug("文件上传成功，{}",fileName);
                    return Result.ok(fileName);
                }
                return Result.ok();
            }
            //保存文件到本地
            image.transferTo(new File(IMAGE_UPLOAD_DIR,fileName));
            //TODO 保存Redis记录
            stringRedisTemplate.opsForSet().add(UPLOAD_FILE_SET,fileName);
            //返回结果
            log.debug("文件上传成功，{}",fileName);
            return Result.ok(fileName);
        }catch (IOException e){
            throw new RuntimeException("文件上传失败!",e);
        }
    }

    @Deprecated
//    @GetMapping("/blog/delete")
    public Result deleteBlogImage1(@RequestParam("name") String fileName){
        File file = new File(IMAGE_UPLOAD_DIR, fileName);
        if (file.isDirectory()) {
            return Result.fail("文件名称错误!");
        }
        FileUtil.del(file);
        return Result.ok();
    }

    /**
     * 清除图片
     * @param filePath 图片链接
     */
    public void delImg(String filePath){
        System.out.println("filePath: "+filePath);
        if (filePath.isBlank()){
            System.out.println("Nooooo, it's blank!");
            return;
        }
        COSUtils.cosClient.deleteObject(SystemConstants.TX_BUCKET_NAME,filePath);
    }

    public boolean delImg1(String filePath){
        File file = new File(IMAGE_UPLOAD_DIR,filePath);
        File parentFile = file.getParentFile();
        File grandparentFile = parentFile.getParentFile();
        if (file.isDirectory()) {
            return false;
        }
        FileUtil.del(file);
        if(!FileUtil.isNotEmpty(parentFile)){
            FileUtil.del(parentFile);
        }
        if(!FileUtil.isNotEmpty(grandparentFile)){
            FileUtil.del(grandparentFile);
        }
        return true;
    }


    /**
     * 生成一个由哈希值组成的文件路径，增强系统安全性
     * @param originalFilename 原始文件名
     * @return 生成的路径
     */
    private String createNewFileName(String originalFilename) {
        String suffix = StrUtil.subAfter(originalFilename, ".", true);
        //生成随机目录
        String name = UUID.randomUUID().toString();
        int hash = name.hashCode();
        int i1 = hash & 0xF;
        int i2 = (hash>>4) & 0xF;
        //本地创建文件夹
//        File dir = new File(IMAGE_UPLOAD_DIR, StrUtil.format("/{}/{}", i1, i2));
//        if (!dir.exists()) {
//            dir.mkdirs();
//        }
        //拼接文件名，并返回
        return StrUtil.format("/{}/{}/{}.{}",i1,i2,name,suffix);
    }


}
